<!--
 * @description: 
 * @Author: FengKongLi
 * @Date: 2022-07-20 17:47:57
 * @LastEditors: FengKongLi
 * @LastEditTime: 2022-07-29 11:24:30
-->
<template>
  <div class="BaseDrawing">
    <div id="cesiumContainer"></div>
    <div class="toolbar">
      <span class="toolbar-item" @click="toLocation">定位位置</span>
      <span class="toolbar-item" @click="handlerDraw('point')">绘制点</span>
      <span class="toolbar-item" @click="handlerDraw('polyline')">绘制线</span>
      <span class="toolbar-item" @click="handlerDraw('polygon')">绘制面</span>
      <span class="toolbar-item" @click="clearDrawEntities">清除</span>

      <span class="toolbar-item" @click="handlerRealTimeDraw('polyline')"
        >实时绘制线</span
      >
      <span class="toolbar-item" @click="handlerRealTimeDraw('polygon')"
        >实时绘制面</span
      >
      <div class="toolbar-tip">
        <div>Left click to add a vertex.</div>
        <div>Right click to start new shape.</div>
      </div>
    </div>
  </div>
</template>

<script>
import { Alert } from "view-design";
export default {
  name: "BaseDrawing",
  data() {
    return {
      viewer: "",
      tempEntities: [],
      // 实时绘制用到的变量
      drawingMode: "line",
      activeShapePoints: [],
      activeShape: "",
      floatingPoint: "",
    };
  },
  mounted() {
    this.init();
  },
  methods: {
    init() {
      Cesium.Ion.defaultAccessToken =
        "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI3NTRlZTllYi0zMjQ3LTRjYzItOGViOS1kYmVjNjAyOTA5ODEiLCJpZCI6OTk0NTAsImlhdCI6MTY1NjQ5NTE4Nn0.BeOLKnxflcj0ztuG4RYdvR8xbXGV7cfEZQWq8Hu7Epw";
      this.viewer = new Cesium.Viewer("cesiumContainer", {
        animation: false, //是否显示动画控件
        timeline: false, //是否显示时间线控件
        navigationHelpButton: false, //是否显示帮助信息控件
        shouldAnimate: true,
        terrainProvider: Cesium.createWorldTerrain(),
      });
      //   去掉版权信息
      this.viewer._cesiumWidget._creditContainer.style.display = "none";
    },
    toLocation() {
      // this.viewer.camera.flyTo({
      //   destination: Cesium.Cartesian3.fromDegrees(121.62, 31.19, 150),
      //   orientation: {
      //     heading: Cesium.Math.toRadians(175.0),
      //     pitch: Cesium.Math.toRadians(-35.0),
      //     roll: 0.0,
      //   },
      // });

      // const center = Cesium.Cartesian3.fromDegrees(121.36, 31.11);
      // // 设置一个水平旋转视口方向的角度
      // const heading = Cesium.Math.toRadians(0);
      // // 设置一个垂直旋转视口的角度
      // const pitch = Cesium.Math.toRadians(-90);
      // // 设置相机距离目标的高度
      // const range = 500;
      // this.viewer.camera.lookAt(
      //   center,
      //   new Cesium.HeadingPitchRange(heading, pitch, range)
      // );

      // Zoom in to an area with mountains
      this.viewer.camera.lookAt(
        Cesium.Cartesian3.fromDegrees(-122.2058, 46.1955, 1000.0),
        new Cesium.Cartesian3(5000.0, 5000.0, 5000.0)
      );
      this.viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);

      // const entity = this.viewer.entities.add({
      //   position: Cesium.Cartesian3.fromDegrees(121.62, 31.19, 40),
      //   point: {
      //     pixelSize: 10,
      //     color: new Cesium.Color(0, 1, 0, 1),
      //   },
      // });
    },
    handlerDraw(type) {
      //绘制点
      let that = this;
      let viewer = this.viewer;
      let tempEntities = this.tempEntities;
      let position = [];
      let tempPoints = [];
      // 开启深度检测
      viewer.scene.globe.depthTestAgainstTerrain = true;
      let canvas = viewer.scene.canvas;
      let handler = new Cesium.ScreenSpaceEventHandler(canvas);
      switch (type) {
        case "point":
          // 监听鼠标左键
          handler.setInputAction(function (movement) {
            // 从相机位置通过windowPosition世界坐标中的像素创建一条射线。返回Cartesian3射线的位置和方向
            let ray = viewer.camera.getPickRay(movement.position);
            // 查找射线与渲染的地球表面之间的交点。射线必须以世界坐标给出。返回Cartesian3对象
            position = viewer.scene.globe.pick(ray, viewer.scene);
            let point = that.drawPoint(position);
            tempEntities.push(point);
          }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
          // 左键双击停止绘制
          handler.setInputAction(function () {
            // 关闭事件句柄
            handler.destroy();
            handler = null;
          }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
          // 右键单击停止绘制
          handler.setInputAction(function () {
            // 关闭事件句柄
            handler.destroy();
            handler = null;
          }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
          break;
        case "polyline":
          // 鼠标移动事件
          handler.setInputAction(function (movement) {},
          Cesium.ScreenSpaceEventType.MOUSE_MOVE);
          // 鼠标左键点击操作
          handler.setInputAction(function (movement) {
            // 调用获取位置信息的接口，跟绘制点获取位置一样
            let ray = viewer.camera.getPickRay(movement.position);
            position = viewer.scene.globe.pick(ray, viewer.scene);
            tempPoints.push(position);
            //调用绘制点的方法
            let point = that.drawPoint(tempPoints[tempPoints.length - 1]);
            tempEntities.push(point);
            if (tempPoints.length > 1) {
              let pointline = that.drawPolyline([
                tempPoints[tempPoints.length - 2],
                tempPoints[tempPoints.length - 1],
              ]);
              tempEntities.push(pointline);
            } else {
              // tooltip.innerHTML = "请绘制下一个点，右键结束";
            }
          }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
          // 右键点击操作
          handler.setInputAction(function () {
            tempPoints = [];
            // 关闭事件句柄
            handler.destroy();
            handler = null;
          }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
          break;
        case "polygon":
          handler.setInputAction(function (movement) {},
          Cesium.ScreenSpaceEventType.MOUSE_MOVE);
          //  左键点击操作
          handler.setInputAction(function (click) {
            let ray = viewer.camera.getPickRay(click.position);
            position = viewer.scene.globe.pick(ray, viewer.scene);
            tempPoints.push(position);
            let point = that.drawPoint(position);
            tempEntities.push(point);
            if (tempPoints.length > 1) {
              let pointline = that.drawPolyline([
                tempPoints[tempPoints.length - 2],
                tempPoints[tempPoints.length - 1],
              ]);
              tempEntities.push(pointline);
            } else {
              // tooltip.innerHTML = "请绘制下一个点，右键结束";
            }
          }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
          // 右键点击操作
          handler.setInputAction(function (click) {
            // pickEllipsoid 选择一个椭球体或地图
            // 如果选择了椭球体或地图，则以世界坐标返回椭球体或地图表面上的点。如果未选取椭球体或地图，则返回未定义。
            let cartesian = viewer.camera.pickEllipsoid(
              click.position,
              viewer.scene.globe.ellipsoid
            );
            if (cartesian) {
              if (tempPoints.length < 3) {
                alert("请绘制3个以上的点再执行闭合操作命令");
              } else {
                // 闭合最后一条线
                let pointline = that.drawPolyline([
                  tempPoints[tempPoints.length - 1],
                  tempPoints[0],
                ]);
                tempEntities.push(pointline);
                that.drawPolygon(tempPoints);
                tempEntities.push(tempPoints);
                handler.destroy();
                handler = null;
              }
            }
          }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

          break;
        default:
          break;
      }
    },
    drawPoint(position, config) {
      let config_ = config ? config : {};
      let viewer = this.viewer;
      let pointGeometry = viewer.entities.add({
        name: "点几何对象",
        position: position,
        point: {
          color: Cesium.Color.SKYBLUE,
          pixelSize: 10,
          outlineColor: Cesium.Color.YELLOW,
          outlineWidth: 3,
          disableDepthTestDistance: Number.POSITIVE_INFINITY,
        },
      });
      return pointGeometry;
    },
    drawPolyline(positions, config_) {
      if (positions.length < 1) return;
      let config = config_ ? config_ : {};
      let viewer = this.viewer;
      let polylineGeometry = viewer.entities.add({
        name: "线几何对象",
        polyline: {
          positions: positions,
          width: config.width ? config.width : 5.0,
          material: new Cesium.PolylineGlowMaterialProperty({
            color: config.color
              ? new Cesium.Color.fromCssColorString(config.color)
              : Cesium.Color.GOLD,
          }),
          // 获取或设置 指定在深度测试失败时 用于绘制折线的材质的属性。
          depthFailMaterial: new Cesium.PolylineGlowMaterialProperty({
            color: config.color
              ? new Cesium.Color.fromCssColorString(config.color)
              : Cesium.Color.GOLD,
          }),
          // 获取或设置布尔属性，该属性指定折线是否应固定在地面上。
          clampToGround: true,
        },
      });
      return polylineGeometry;
    },
    drawPolygon(positions, config_) {
      let viewer = this.viewer;
      if (positions.length < 2) return;
      let config = config_ ? config_ : {};
      return viewer.entities.add({
        name: "面几何对象",
        polygon: {
          hierarchy: positions,
          // fromCssColorString从 CSS 颜色值创建一个 Color 实例。
          material: config.color
            ? new Cesium.Color.fromCssColorString(config.color).withAlpha(0.2)
            : new Cesium.Color.fromCssColorString("#FFD700").withAlpha(0.2),
        },
      });
    },
    clearDrawEntities() {
      let viewer = this.viewer;
      this.tempEntities = [];
      // 清除之前的实体
      const entities = viewer.entities._entities._array;
      // 倒叙遍历防止实体减少之后entities[f]不存在
      for (let i = entities.length - 1; i >= 0; i--) {
        if (
          entities[i]._name &&
          (entities[i]._name == "点几何对象" ||
            entities[i]._name == "线几何对象" ||
            entities[i]._name == "面几何对象")
        ) {
          viewer.entities.remove(entities[i]);
        }
      }
    },
    handlerRealTimeDraw(drawingMode) {
      let that = this;
      that.drawingMode = drawingMode;
      let viewer = this.viewer;

      if (!viewer.scene.pickPositionSupported) {
        window.alert("This browser does not support pickPosition.");
      }
      // cesiumWidget一个包含 Cesium 场景的小部件。//双击鼠标左键清除默认事件
      viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
        Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
      );
      let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
      // 左键点击操作
      handler.setInputAction(function (event) {
        // We use `viewer.scene.pickPosition` here instead of `viewer.camera.pickEllipsoid` so that
        // we get the correct point when mousing over terrain.
        const earthPosition = viewer.scene.pickPosition(event.position);
        // `earthPosition` will be undefined if our mouse is not over the globe.
        if (Cesium.defined(earthPosition)) {
          if (that.activeShapePoints.length === 0) {
            that.floatingPoint = that.createPoint(earthPosition);
            that.activeShapePoints.push(earthPosition);
            const dynamicPositions = new Cesium.CallbackProperty(function () {
              if (that.drawingMode === "polygon") {
                return new Cesium.PolygonHierarchy(that.activeShapePoints);
              }
              return that.activeShapePoints;
            }, false);
            that.activeShape = that.drawShape(dynamicPositions);
          }
          that.activeShapePoints.push(earthPosition);
          that.createPoint(earthPosition);
        }
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
      // 鼠标移动操作
      handler.setInputAction(function (event) {
        if (Cesium.defined(that.floatingPoint)) {
          const newPosition = viewer.scene.pickPosition(event.endPosition);
          if (Cesium.defined(newPosition)) {
            that.floatingPoint._position.setValue(newPosition);
            that.activeShapePoints.pop();
            that.activeShapePoints.push(newPosition);
          }
        }
      }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
      // 右键操作
      handler.setInputAction(function (event) {
        handler.destroy();
        handler = null;
        that.terminateShape();
      }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    },
    createPoint(worldPosition) {
      let viewer = this.viewer;
      const point = viewer.entities.add({
        name: "点几何对象",
        position: worldPosition,
        point: {
          color: Cesium.Color.SKYBLUE,
          pixelSize: 10,
          // heightReference获取或设置指定 HeightReference 的 Property。
          // HeightReference表示相对于地形的位置。CLAMP_TO_GROUND表示贴地
          heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
        },
      });
      return point;
    },
    drawShape(positionData) {
      let shape;
      if (this.drawingMode === "polyline") {
        shape = this.viewer.entities.add({
          name: "线几何对象",
          polyline: {
            positions: positionData,
            clampToGround: true,
            width: 3,
          },
        });
      } else if (this.drawingMode === "polygon") {
        shape = this.viewer.entities.add({
          name: "面几何对象",
          polygon: {
            hierarchy: positionData,
            material: new Cesium.ColorMaterialProperty(
              Cesium.Color.SKYBLUE.withAlpha(0.7)
            ),
          },
        });
      }
      return shape;
    },
    // Redraw the shape so it's not dynamic and remove the dynamic shape.
    terminateShape() {
      this.activeShapePoints.pop();
      this.drawShape(this.activeShapePoints);
      this.viewer.entities.remove(this.floatingPoint);
      this.viewer.entities.remove(this.activeShape);
      this.floatingPoint = undefined;
      this.activeShape = undefined;
      this.activeShapePoints = [];
    },
  },
};
</script>
<style lang="scss" scoped>
.BaseDrawing {
  position: relative;
  #cesiumContainer {
    width: 100%;
    height: 100vh;
    margin: 0;
    padding: 0px;
    overflow: hidden;
  }
  .toolbar {
    position: absolute;
    top: 1rem;
    // background: rgb(12, 187, 245);
    &-item {
      background: rgb(91, 92, 92);
      margin: 1rem 1rem;
      padding: 1rem 1rem;
      color: white;
      font-size: 1rem;
    }
    &-tip {
      margin: 1rem;
      color: aquamarine;
    }
  }
}
</style>
